package com.tjhk.geoserver.api.service;

import com.tjhk.geoserver.api.config.GeoserverProperties;
import com.tjhk.geoserver.api.util.FileUtil;
import it.geosolutions.geoserver.rest.GeoServerRESTManager;
import it.geosolutions.geoserver.rest.GeoServerRESTPublisher;
import it.geosolutions.geoserver.rest.GeoServerRESTReader;
import it.geosolutions.geoserver.rest.decoder.RESTDataStore;
import it.geosolutions.geoserver.rest.decoder.RESTLayer;
import it.geosolutions.geoserver.rest.encoder.GSResourceEncoder;
import it.geosolutions.geoserver.rest.encoder.datastore.GSGeoTIFFDatastoreEncoder;
import it.geosolutions.geoserver.rest.encoder.datastore.GSShapefileDatastoreEncoder;
import it.geosolutions.geoserver.rest.manager.GeoServerRESTStyleManager;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.gce.geotiff.GeoTiffReader;
import org.geotools.referencing.CRS;
import org.opengis.feature.GeometryAttribute;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.type.GeometryType;
import org.opengis.feature.type.Name;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.List;
import java.util.UUID;

public class GeoServer {

    public static final Logger log = LoggerFactory.getLogger(GeoServer.class.getName());

    public java.net.URL URL;

    public GeoServerRESTManager manager;

    public GeoServerRESTReader reader;

    public GeoServerRESTPublisher publisher;

    public GeoServer(GeoserverProperties geoserverProperties) {
        try {
            URL = new URL(geoserverProperties.getUrl());
            manager = new GeoServerRESTManager(URL, geoserverProperties.getUser(), geoserverProperties.getPassword());
            reader = manager.getReader();
            publisher = manager.getPublisher();
            log.info("GeoServer-Manager Build Success");
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }
    public boolean creatWorkplace(String workplace){
        GeoServerRESTPublisher publisher = manager.getPublisher();
        List<String> workspaces = manager.getReader().getWorkspaceNames();
        if (!workspaces.contains(workplace)) {
            boolean created = publisher.createWorkspace(workplace);
            System.out.println("create ws : " + created);
            log.info("create workplace : {},",workplace,created);
        } else {
            log.info("workspace已经存在了,ws :{},",workplace);
        }
        return true;
    }
    public boolean publicShp(String workplace, File zipFile, String randomLayerName, String styleName){
        try {
//            String basePath = System.getProperty("user.dir");
//            String zipFilePath = basePath + "\\tmp\\zip\\";

            String zipFilePath =  "tmp"+File.separator+"zip"+File.separator;
            String oldFileName = zipFile.getName().substring(0,zipFile.getName().lastIndexOf("."));
            String filePath = zipFilePath + oldFileName;
            FileUtil.delDir(filePath);
            FileUtil.unZipFiles(zipFile.getPath(),filePath);
//            FileUtil.unZip(file2,filePath);
            File file = new File(filePath);
            File[] fs = file.listFiles();
            String shpName = null;
            String srs = null;
            for(File f : fs){
                if(f.isFile())
                {
                    if (f.getName().endsWith(".shp")){
                        shpName = f.getName().replaceAll("[.][^.]+$", "");
                        srs = getShpSrs(f);
                        log.info("shpInfo,name: {},SRS: {}",f.getName(),srs);
                    }
                }
            }
            if (shpName!=null){
                String newFilePath = zipFilePath + randomLayerName;
                // 创建文件夹
                (new File(newFilePath)).mkdirs();
                for(File f : fs){
                    if(f.isFile()){
                        String fileType=FileUtil.getFileType(f.getName());
                        FileUtil.copyFile(f, newFilePath + File.separator + randomLayerName+fileType);
                    }
                }
                boolean flag = FileUtil.fileToZip(newFilePath,zipFilePath,randomLayerName+".zip");
                log.info("new shpfile->zipfile,zipfile:{},flag:{}",zipFilePath+ File.separator + randomLayerName+".zip",flag);
                boolean published = publicShp(workplace, randomLayerName, randomLayerName, new File(zipFilePath+ File.separator + randomLayerName+".zip"), srs == null?GeoServerRESTPublisher.DEFAULT_CRS:srs, styleName);
                return published;
            }
        }catch (Exception e){
            return false;
        }
        return true;
    }
    public boolean publicShp(String workplace, File zipFile, String styleName){
        try {
            String basePath = System.getProperty("user.dir");
//            String zipFilePath = basePath + "\\tmp\\zip\\";
//            String zipFilePath =  "\\tmp\\zip\\";
            String zipFilePath =  "tmp"+File.separator+"zip"+File.separator;
            String oldFileName = zipFile.getName().substring(0,zipFile.getName().lastIndexOf("."));
            String filePath = zipFilePath + oldFileName;
            FileUtil.delDir(filePath);
            FileUtil.unZipFiles(zipFile.getPath(),filePath);
//            FileUtil.unZip(file2,filePath);
            File file = new File(filePath);
            File[] fs = file.listFiles();
            String shpName = null;
            String srs = null;
            for(File f : fs){
                if(f.isFile())
                {
                    if (f.getName().endsWith(".shp")){
                        shpName = f.getName().replaceAll("[.][^.]+$", "");
                        srs = getShpSrs(f);
                        log.info("shpInfo,name: {},SRS: {}",f.getName(),srs);
                    }
                }
            }
            if (shpName!=null){
                String randomLayerName = UUID.randomUUID().toString().replaceAll("-","");
                String newFilePath = zipFilePath + randomLayerName;
                // 创建文件夹
                (new File(newFilePath)).mkdirs();
                for(File f : fs){
                    if(f.isFile()){
                        String fileType=FileUtil.getFileType(f.getName());
                        FileUtil.copyFile(f, newFilePath + File.separator + randomLayerName+fileType);
                    }
                }
                boolean flag = FileUtil.fileToZip(newFilePath,zipFilePath,randomLayerName+".zip");
                log.info("new shpfile->zipfile,zipfile:{},flag:{}",zipFilePath+ File.separator + randomLayerName+".zip",flag);
                boolean published = publicShp(workplace, randomLayerName, randomLayerName, new File(zipFilePath+ File.separator + randomLayerName+".zip"), srs == null?GeoServerRESTPublisher.DEFAULT_CRS:srs, styleName);
                System.out.println(published);
            }
        }catch (Exception e){
            return false;
        }
        return true;
    }
    public boolean publicShp(String workplace, String store_name, String layerName, File zipFile, String srs, String styleName){
        try {
            creatWorkplace(workplace);
            //shp文件所在的位置
            String urlDataStore = "file://"+zipFile.getAbsolutePath().substring(0,zipFile.getAbsolutePath().lastIndexOf("."))+File.separator+".shp";
            //判断数据存储（dataStore）是否已经存在，不存在则创建
            URL shpFileUrl = new URL(urlDataStore);
            RESTDataStore restStore = reader.getDatastore(workplace, store_name);
            if (restStore == null) {
                //创建shape文件存储
                GSShapefileDatastoreEncoder store = new GSShapefileDatastoreEncoder(store_name, shpFileUrl);
                boolean createStore = manager.getStoreManager().create(workplace, store);
                log.info("create store : {},flag:{}",store_name,createStore);
            } else {
                log.warn("数据存储已经存在了,store: {}",store_name);
            }
            //判断图层是否已经存在，不存在则创建并发布
            RESTLayer layer = reader.getLayer(workplace, layerName);
            if (layer == null) {
                //发布图层
                boolean publish = manager.getPublisher().publishShp(workplace, store_name, layerName, zipFile, srs,styleName);
                log.info("图层[{}]发布: {}",layerName,publish);
                return publish;
            } else {
                log.warn("图层[{}]已经发布过了,请删除后重新发布！",layerName);
            }
        }catch (Exception e){
            log.warn("图层[{}]发布失败,error:{}",layerName,e);
        }
        return false;
    }

    public boolean publicTiff(String workplace, String store_name, String layerName, File file, String styleName){
        try {
            GeoTiffReader reader=new GeoTiffReader(file);
            CoordinateReferenceSystem coordinate = reader.getCoordinateReferenceSystem();
            String srs = getCodeFromCrs(coordinate);
            if (srs.contains("null")){
                srs = "EPSG:4326";
            }
            System.out.println(srs);
            publicTiff(workplace, store_name, layerName, file, srs,styleName);
        }catch (Exception e){
            return false;
        }
        return true;
    }

    public boolean publicTiff(String workplace, String store_name, String layerName, File file, String coordinate ,String styleName){
        try {
            creatWorkplace(workplace);
            store_name = store_name.replaceAll("[.][^.]+$", "");
            RESTDataStore restStore = manager.getReader().getDatastore(workplace, URLEncoder.encode(store_name));
            if (restStore == null) {
                GSGeoTIFFDatastoreEncoder gsGeoTIFFDatastoreEncoder = new GSGeoTIFFDatastoreEncoder(store_name);
                gsGeoTIFFDatastoreEncoder.setWorkspaceName(workplace);
                gsGeoTIFFDatastoreEncoder.setUrl(new URL("file:" + store_name));
                boolean createStore = manager.getStoreManager().create(workplace, gsGeoTIFFDatastoreEncoder);
                System.out.println("publish createStore : " + createStore);
                boolean publish = publisher.publishGeoTIFF(workplace,
                        URLEncoder.encode(store_name),
                        layerName,
                        file,
                        coordinate,
                        GSResourceEncoder.ProjectionPolicy.FORCE_DECLARED,
                        workplace+":"+styleName,
                        null);
                System.out.println("publish (TIFF文件发布状态) : " + publish);
                //System.out.println(f.getName() + " : 发布成功！");
            } else {
                System.out.println("数据存储已经存在了,store:" + store_name);
            }
        }catch (Exception e){
            return false;
        }
        return true;
    }

    public boolean publicTiff(String workplace, String layerName,  File file){
        //GeoServer的连接配置
        try {
            creatWorkplace(workplace);
            layerName = layerName.replaceAll("[.][^.]+$", "");
            String storeName = layerName;
            RESTDataStore restStore = manager.getReader().getDatastore(workplace, URLEncoder.encode(storeName));
            if (restStore == null) {
                GSGeoTIFFDatastoreEncoder gsGeoTIFFDatastoreEncoder = new GSGeoTIFFDatastoreEncoder(storeName);
                gsGeoTIFFDatastoreEncoder.setWorkspaceName(workplace);
                gsGeoTIFFDatastoreEncoder.setUrl(new URL("file:" + layerName));
                boolean createStore = manager.getStoreManager().create(workplace, gsGeoTIFFDatastoreEncoder);
                boolean publish = manager.getPublisher()
                        .publishGeoTIFF(workplace, URLEncoder.encode(layerName), file);
                System.out.println("publish (TIFF文件发布状态) : " + publish);
                //System.out.println(f.getName() + " : 发布成功！");
            } else {
                System.out.println("数据存储已经存在了,store:" + layerName);
            }
        }catch (Exception e){
            return false;
        }
        return true;
    }

    public boolean deleteTiff(String workplace, String store_name){
        return deleteTiff(workplace, store_name,  store_name);
    }

    public boolean deleteTiff(String workplace, String store_name,  String layerName){
        //GeoServer的连接配置
        try {
            manager.getPublisher().removeLayer(workplace,URLEncoder.encode(layerName));
            GSGeoTIFFDatastoreEncoder gsGeoTIFFDatastoreEncoder = new GSGeoTIFFDatastoreEncoder(URLEncoder.encode(store_name));
            gsGeoTIFFDatastoreEncoder.setWorkspaceName(workplace);
            manager.getStoreManager().remove(workplace,gsGeoTIFFDatastoreEncoder,true);
//            System.out.println("图层已删除,store:" + store_name+" flag: "+flag);
        }catch (Exception e){
            return false;
        }
        return true;
    }

    public boolean deleteLayer(String workplace, String store_name){
        return publisher.removeLayer(workplace, URLEncoder.encode(store_name));
    }

    public boolean deleteStore(String workplace, String store_name){
        GSGeoTIFFDatastoreEncoder gsGeoTIFFDatastoreEncoder = new GSGeoTIFFDatastoreEncoder(URLEncoder.encode(store_name));
        gsGeoTIFFDatastoreEncoder.setWorkspaceName(workplace);
        try {
            return manager.getStoreManager().remove(workplace,gsGeoTIFFDatastoreEncoder,true);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return false;
    }

    public boolean publishStyle(String workplace, String styleName,  File file){
        //GeoServer的连接配置
        try {
            creatWorkplace(workplace);
            GeoServerRESTStyleManager styleManager = manager.getStyleManager();
            if (!styleManager.existsStyle(workplace,styleName)) {
                // 向geoserver写入style
                boolean publishStyleInWorkspace = styleManager.publishStyleInWorkspace(workplace, file, styleName);
                System.out.println("publishStyleInWorkspace : "+publishStyleInWorkspace);
            }
        }catch (Exception e){
            return false;
        }
        return true;
    }

    public boolean isExistLayer(String workplace, String layerName){
        //GeoServer的连接配置
        try {
            RESTLayer restLayer = manager.getReader().getLayer(workplace, URLEncoder.encode(layerName));
            if (restLayer!=null) {
                return true;
            }
        }catch (Exception e){
            return false;
        }
        return false;
    }

    public boolean isExistStyle(String workplace, String styleName){
        //GeoServer的连接配置
        try {
            GeoServerRESTStyleManager styleManager = manager.getStyleManager();
            if (styleManager.existsStyle(workplace,styleName)) {
                return true;
            }
        }catch (Exception e){
            return false;
        }
        return false;
    }
    private String getShpSrs(File shpFile){
        try {
            // 读取到数据存储中
            FileDataStore dataStore = FileDataStoreFinder.getDataStore(shpFile);
            CoordinateReferenceSystem coordinateReferenceSystem = dataStore.getSchema().getCoordinateReferenceSystem();
            String srs = getCodeFromCrs(coordinateReferenceSystem);
            dataStore.dispose();//使用之后必须关掉
            return srs;
        }catch (Exception e){
            log.error("获取Shp文件信息错误！，err:{}",e.toString());
        }
        return null;
    }

    public static String getCodeFromCrs( CoordinateReferenceSystem crs ) throws Exception {
        String code = null;
        try {
            System.out.println(crs.toWKT());
            System.out.println(CRS.toSRS(crs));
            String crss = CRS.toSRS(crs);
            if (crss.contains("PCS")){
                System.out.println(crss.split("=")[1].trim());
                if (crss.split("=")[1].trim().equals("CGCS2000_3_Degree_GK_CM_117E")){
                    return "EPSG:4548";
                }
            }
            Integer epsg = CRS.lookupEpsgCode(crs, true);
            code = "EPSG:" + epsg; //$NON-NLS-1$
        } catch (Exception e) {
            // try non epsg
            code = CRS.lookupIdentifier(crs, true);
        }
        return code;
    }

    private void printShpInfo(File shpFile){
        try {
            // 读取到数据存储中
            FileDataStore dataStore = FileDataStoreFinder.getDataStore(shpFile);
            // 获取特征资源
            SimpleFeatureSource simpleFeatureSource = dataStore.getFeatureSource();
            // 要素集合
            SimpleFeatureCollection simpleFeatureCollection = simpleFeatureSource.getFeatures();

            // 要素数量
            int featureSize = simpleFeatureCollection.size();
            // 获取要素迭代器
            SimpleFeatureIterator featureIterator = simpleFeatureCollection.features();
            if(featureIterator.hasNext()){
                // 要素对象
                SimpleFeature feature = featureIterator.next();
                // 要素属性信息，名称，值，类型
                List<Property> propertyList = (List<Property>) feature.getValue();
                for(Property property : propertyList){
                    log.info("shpInfo-property: 属性名称：{},属性值：{},属性类型：{}",property.getName(),property.getValue(),property.getType());
                }
                // 要素属性信息
                List<Object> featureAttributes = feature.getAttributes();
                // 要素geometry的类型和坐标，如点，线，面及其组成的坐标
                Object geometryText = feature.getDefaultGeometry();
                // geometry属性
                GeometryAttribute geometryAttribute = feature.getDefaultGeometryProperty();
                // 获取坐标参考系信息
                CoordinateReferenceSystem coordinateReferenceSystem = geometryAttribute.getDescriptor().getCoordinateReferenceSystem();
                // geometry类型
                GeometryType geometryType = geometryAttribute.getType();
                // geometry类型名称
                Name name = geometryType.getName();
                log.info("shpInfo-feature: 要素数量：{},要素属性：{},要素geometry位置信息：{},要素geometry类型名称：{},shp文件使用的坐标参考系：{}",
                        featureSize,featureAttributes,geometryText,name,coordinateReferenceSystem);

            }
            featureIterator.close();
            dataStore.dispose();//使用之后必须关掉
        }catch (Exception e){
            log.error("获取Shp文件信息错误！，err:{}",e.toString());
        }
    };
}
